package com.fileupload.thread;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程管理器<br>
 * 提供统一的线程池管理机制，负责创建、提交和取消任务，管理线程生命周期<br>
 * 该组件是系统中所有异步操作的核心调度中心，确保高效的资源利用和线程安全
 * 
 * @author 小乙
 * @version 1.0
 * @since 2024-01-01
 */
@Component
public class ThreadManager {
    /**
     * 日志记录器
     */
    private static final Logger logger = LoggerFactory.getLogger(ThreadManager.class);
    
    // 核心线程数
    private static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2;
    
    // 最大线程数
    private static final int MAX_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 4;
    
    // 线程存活时间
    private static final long KEEP_ALIVE_TIME = 60L;
    
    // 线程池名称前缀
    private static final String THREAD_NAME_PREFIX = "file-upload-";
    
    /**
     * 线程池 - 核心执行引擎，管理系统中所有异步任务
     */
    private final ExecutorService executorService;
    
    /**
     * 任务映射表 - 存储任务ID与Future对象的映射，用于跟踪和取消任务
     */
    private final Map<String, Future<?>> taskFutures;
    
    // 线程工厂
    private final ThreadFactory threadFactory;
    
    /**
     * 构造函数 - 初始化线程池和相关资源
     * <p>
     * 根据系统可用处理器数量动态配置线程池参数，确保高效的任务处理能力。
     * 使用LinkedBlockingQueue作为工作队列，CallerRunsPolicy作为拒绝策略，
     * 当队列满时由调用者执行任务，避免任务丢失。
     * </p>
     */
    public ThreadManager() {
        // 线程工厂，用于创建命名线程
        this.threadFactory = new NamedThreadFactory();
        
        // 线程池配置
        this.executorService = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1024),
                threadFactory,
                new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略：由调用者执行
        );
        
        // 线程跟踪映射
        this.taskFutures = new ConcurrentHashMap<>();
        
        logger.info("线程管理器初始化成功，核心线程数: {}, 最大线程数: {}", CORE_POOL_SIZE, MAX_POOL_SIZE);
    }
    
    /**
     * 提交任务到线程池
     * <p>
     * 根据任务名称提交Runnable任务到线程池执行，并保存任务引用以便后续跟踪和取消。
     * 如果同名任务已在运行中，则不会重复提交。
     * </p>
     * 
     * @param taskName 任务名称，用于唯一标识任务
     * @param task 要执行的任务
     * @return 任务的Future对象
     */
    public Future<?> submitTask(String taskName, Runnable task) {
        if (taskName == null || task == null) {
            logger.warn("任务名称或任务不能为空");
            return null;
        }
        
        // 检查是否已存在同名任务
        Future<?> existingFuture = taskFutures.get(taskName);
        if (existingFuture != null && !existingFuture.isDone() && !existingFuture.isCancelled()) {
            logger.warn("任务 [{}] 已在运行中，无需重复提交", taskName);
            return existingFuture;
        }
        
        // 提交任务并保存引用
        Future<?> future = executorService.submit(() -> {
            try {
                task.run();
            } catch (Exception e) {
                logger.error("执行任务 [{}] 时发生异常: {}", taskName, e.getMessage(), e);
            } finally {
                taskFutures.remove(taskName);
            }
        });
        taskFutures.put(taskName, future);
        logger.info("任务 [{}] 已提交到线程池", taskName);
        return future;
    }
    
    /**
     * 提交有返回值的任务到线程池
     * <p>
     * 根据任务名称提交Callable任务到线程池执行，并保存任务引用以便后续跟踪和取消。
     * 如果同名任务已在运行中，则不会重复提交。
     * </p>
     * 
     * @param taskName 任务名称，用于唯一标识任务
     * @param task 要执行的有返回值任务
     * @return 任务执行结果的Future对象
     */
    @SuppressWarnings("unchecked")
    public <T> Future<T> submitTask(String taskName, Callable<T> task) {
        if (taskName == null || task == null) {
            logger.warn("任务名称或任务不能为空");
            return null;
        }
        
        // 检查是否已存在同名任务
        Future<?> existingFuture = taskFutures.get(taskName);
        if (existingFuture != null && !existingFuture.isDone() && !existingFuture.isCancelled()) {
            logger.warn("任务 [{}] 已在运行中，无需重复提交", taskName);
            return null;
        }
        
        // 提交任务并保存引用
        Future<T> future = executorService.submit(() -> {
            try {
                return task.call();
            } catch (Exception e) {
                logger.error("执行任务 [{}] 时发生异常: {}", taskName, e.getMessage(), e);
                throw e;
            } finally {
                taskFutures.remove(taskName);
            }
        });
        taskFutures.put(taskName, future);
        logger.info("有返回值的任务 [{}] 已提交到线程池", taskName);
        return future;
    }
    
    /**
     * 取消任务（不中断正在运行的任务）
     * <p>
     * 根据任务名称取消正在等待执行的任务。如果任务已开始执行，则不会中断。
     * 如果任务已完成或已取消，则返回false。取消成功后，会从任务映射表中移除该任务的引用。
     * </p>
     * 
     * @param taskName 任务名称
     * @return 是否成功取消任务
     */
    public boolean cancelTask(String taskName) {
        return cancelTask(taskName, false);
    }
    
    /**
     * 取消任务
     * <p>
     * 根据任务名称取消正在执行或等待执行的任务。如果任务已完成或已取消，则返回false。
     * 取消成功后，会从任务映射表中移除该任务的引用。
     * </p>
     * 
     * @param taskName 任务名称
     * @param mayInterruptIfRunning 是否允许中断正在运行的任务
     * @return 是否成功取消任务
     */
    public boolean cancelTask(String taskName, boolean mayInterruptIfRunning) {
        Future<?> future = taskFutures.get(taskName);
        if (future != null) {
            boolean result = future.cancel(mayInterruptIfRunning);
            if (result) {
                taskFutures.remove(taskName);
                logger.info("任务 [{}] 已取消", taskName);
            } else {
                logger.warn("任务 [{}] 取消失败", taskName);
            }
            return result;
        }
        return false;
    }
    
    /**
     * 检查任务是否在运行
     * <p>
     * 根据任务名称检查任务是否正在执行中。如果任务已完成或已取消，则返回false。
     * </p>
     * 
     * @param taskName 任务名称
     * @return 任务是否在运行中
     */
    public boolean isTaskRunning(String taskName) {
        Future<?> future = taskFutures.get(taskName);
        return future != null && !future.isDone() && !future.isCancelled();
    }
    
    /**
     * 关闭线程管理器
     * <p>
     * 安全地关闭线程管理器，包括取消所有任务和关闭线程池。
     * 首先尝试优雅关闭，如果超时则强制关闭。
     * </p>
     */
    public void shutdown() {
        logger.info("开始关闭线程池...");
        
        // 取消所有任务
        for (Map.Entry<String, Future<?>> entry : taskFutures.entrySet()) {
            String taskName = entry.getKey();
            Future<?> future = entry.getValue();
            if (!future.isDone() && !future.isCancelled()) {
                future.cancel(true);
                logger.info("任务 [{}] 已强制取消", taskName);
            }
        }
        
        // 清空任务映射
        taskFutures.clear();
        
        // 关闭线程池
        executorService.shutdown();
        
        try {
            // 等待线程池关闭，最多等待30秒
            if (!executorService.awaitTermination(30, TimeUnit.SECONDS)) {
                // 如果超时，强制关闭
                executorService.shutdownNow();
                logger.warn("线程池强制关闭");
            } else {
                logger.info("线程池已正常关闭");
            }
        } catch (InterruptedException e) {
            // 等待过程中被中断，强制关闭
            executorService.shutdownNow();
            Thread.currentThread().interrupt();
            logger.warn("线程池关闭过程被中断");
        }
    }
    
    /**
     * 获取线程池状态信息
     * <p>
     * 返回线程池的当前状态，包括活跃线程数、核心线程数、最大线程数等信息，用于监控和调试。
     * </p>
     * 
     * @return 线程池状态描述字符串
     */
    public String getPoolStatus() {
        ThreadPoolExecutor threadPool = (ThreadPoolExecutor) executorService;
        return String.format(
                "线程池状态 - 活跃线程数: %d, 核心线程数: %d, 最大线程数: %d, " +
                "已完成任务数: %d, 任务队列大小: %d, 等待任务数: %d",
                threadPool.getActiveCount(),
                threadPool.getCorePoolSize(),
                threadPool.getMaximumPoolSize(),
                threadPool.getCompletedTaskCount(),
                threadPool.getTaskCount(),
                threadPool.getQueue().size()
        );
    }
    
    /**
     * 线程工厂 - 用于创建具有自定义名称的线程，便于调试和监控
     */
    private static class NamedThreadFactory implements ThreadFactory {
        /**
         * 线程计数器
         */
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        
        /**
         * 创建新线程
         * @param r 要执行的任务
         * @return 创建的新线程
         */
        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r, THREAD_NAME_PREFIX + threadNumber.getAndIncrement());
            thread.setDaemon(false); // 非守护线程，确保任务能够完成
            thread.setPriority(Thread.NORM_PRIORITY); // 正常优先级
            return thread;
        }
    }
}